/******************************************************************************

Flatmap viewer and annotation tool

Copyright (c) 2019 - 2023  David Brooks

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

******************************************************************************/
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _AnnotationService_instances, _AnnotationService_serverEndpoint, _AnnotationService_currentUser, _AnnotationService_currentError, _AnnotationService_request;
import Cookies from 'js-cookie';
//==============================================================================
const SERVER_TIMEOUT = 10000; //  10 seconds
//==============================================================================
/**
 * Interface to a SPARC map annotation service.
 */
export class AnnotationService {
    /**
     * @param  serverEndpoint  The URL of a map annotation service.
     */
    constructor(serverEndpoint) {
        _AnnotationService_instances.add(this);
        _AnnotationService_serverEndpoint.set(this, void 0);
        _AnnotationService_currentUser.set(this, null);
        _AnnotationService_currentError.set(this, null
        /**
         * @param  serverEndpoint  The URL of a map annotation service.
         */
        );
        if (serverEndpoint.slice(-1) === '/') { // Strip any trailing slash
            __classPrivateFieldSet(this, _AnnotationService_serverEndpoint, serverEndpoint.slice(0, -1), "f");
        }
        else {
            __classPrivateFieldSet(this, _AnnotationService_serverEndpoint, serverEndpoint, "f");
        }
    }
    /**
     * Get information about the logged-in SPARC user.
     *
     * Requires {@linkcode authenticate} to first be called.
     */
    get currentUser() {
        return __classPrivateFieldGet(this, _AnnotationService_currentUser, "f");
    }
    /**
     * Get information about any error from the last call
     * to {@linkcode authenticate}.
     */
    get currentError() {
        return __classPrivateFieldGet(this, _AnnotationService_currentError, "f");
    }
    /**
     * Authenticate the logged-in SPARC user.
     *
     * @param  userApiKey  The Api token of the logged-in Pennsieve user
     * @return  A Promise resolving to either data about a valid user
     *          or a reason why the user is invalid.
     */
    async authenticate(userApiKey) {
        __classPrivateFieldSet(this, _AnnotationService_currentError, null, "f");
        __classPrivateFieldSet(this, _AnnotationService_currentUser, null, "f");
        const userData = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'authenticate');
        if (!('error' in userData)) {
            Cookies.set('annotation-key', userData.session, { secure: true, expires: 1 });
            __classPrivateFieldSet(this, _AnnotationService_currentUser, userData.data, "f");
            return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentUser, "f"));
        }
        Cookies.remove('annotation-key');
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
    /**
     * Unauthenticate with the annotation service.
     *
     * @param  userApiKey  The Api token of the logged-in Pennsieve user
     * @return A Promise with data about the call.
     */
    async unauthenticate(userApiKey) {
        __classPrivateFieldSet(this, _AnnotationService_currentError, null, "f");
        __classPrivateFieldSet(this, _AnnotationService_currentUser, null, "f");
        const responseData = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'unauthenticate');
        if ('success' in responseData) {
            return Promise.resolve(responseData);
        }
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
    /**
     * Get identifiers of all annotated items in a resource.
     *
     * @param  userApiKey    The Api token of the logged-in Pennsieve user
     * @param  resourceId    The resource's identifier
     * @param  userId        A user identifier (ORCID). Optional
     * @param  participated  Get items the user was involved in annotating or not.
     *                       Optional, default ``true``
     * @return A Promise resolving to either a list of identifiers of annotated
     *         items or a reason why identifiers couldn't be retrieved.
     */
    async annotatedItemIds(userApiKey, resourceId, userId, participated) {
        const params = {
            resource: resourceId
        };
        if (userId !== undefined) {
            params.user = userId;
        }
        if (participated !== undefined) {
            params.participated = participated;
        }
        const itemIds = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'items/', 'GET', params);
        if (!('error' in itemIds)) {
            return Promise.resolve(itemIds);
        }
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
    /**
     * Get all annotated features drawn on a resource.
     *
     * @param  userApiKey  The Api token of the logged-in Pennsieve user
     * @param  resourceId  The resource's identifier
     * @return             A Promise resolving to either a list of annotated
     *                     features drawn on the resource or a reason why
     *                     features couldn't be retrieved.
     */
    async drawnFeatures(userApiKey, resourceId, itemIds) {
        const params = {
            resource: resourceId
        };
        if (itemIds !== undefined) {
            params.items = itemIds;
        }
        const features = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'features/', 'GET', params);
        if (!('error' in features)) {
            return Promise.resolve(features);
        }
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
    /**
     * Get all annotations about a specific item in a resource.
     *
     * @param  userApiKey  The Api token of the logged-in Pennsieve user
     * @param  resourceId  The resource's identifier
     * @param  itemId      The item's identifier within the resource
     * @return             A Promise resolving to either a list of
     *                     annotations about the item or a reason
     *                     why annotations couldn't be retrieved.
     */
    async itemAnnotations(userApiKey, resourceId, ItemId) {
        const annotations = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'annotations/', 'GET', {
            resource: resourceId,
            item: ItemId
        });
        if (!('error' in annotations)) {
            return Promise.resolve(annotations);
        }
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
    /**
     * Get details of a specific annotation.
     *
     * @param  userApiKey  The Api token of the logged-in Pennsieve user
     * @param  annotationId  The annotation's URI
     * @return               A Promise resolving to either an annotation
     *                       with the given URI or a reason why the
     *                       annotation couldn't be retrieved.
     */
    async annotation(userApiKey, annotationId) {
        const annotation = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, 'annotation/', 'GET', {
            annotation: annotationId
        });
        if (!('error' in annotation)) {
            return Promise.resolve(annotation);
        }
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
    /**
     * Add an annotation about a specific item in a resource.
     *
     * @param  userApiKey  The Api token of the logged-in Pennsieve user
     * @param   annotation  Annotation about the feature
     * @return              A Promise resolving to either the resulting
     *                      full annotation or a reason why the
     *                      annotation couldn't be added
     */
    async addAnnotation(userApiKey, userAnnotation) {
        if (__classPrivateFieldGet(this, _AnnotationService_currentUser, "f") && __classPrivateFieldGet(this, _AnnotationService_currentUser, "f").canUpdate) {
            const annotationRequest = Object.assign({
                creator: __classPrivateFieldGet(this, _AnnotationService_currentUser, "f"),
                created: (new Date()).toISOString()
            }, userAnnotation);
            const annotationResponse = await __classPrivateFieldGet(this, _AnnotationService_instances, "m", _AnnotationService_request).call(this, userApiKey, `annotation/`, 'POST', {
                data: annotationRequest
            });
            if (!('error' in annotationResponse)) {
                return Promise.resolve(annotationResponse);
            }
            __classPrivateFieldSet(this, _AnnotationService_currentError, annotationResponse, "f");
        }
        else {
            __classPrivateFieldSet(this, _AnnotationService_currentError, { error: 'user cannot add annotation' }, "f");
        }
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
}
_AnnotationService_serverEndpoint = new WeakMap(), _AnnotationService_currentUser = new WeakMap(), _AnnotationService_currentError = new WeakMap(), _AnnotationService_instances = new WeakSet(), _AnnotationService_request = async function _AnnotationService_request(userApiKey, endpoint, method = 'GET', parameters = {}) {
    let noResponse = true;
    const abortController = new AbortController();
    setTimeout(() => {
        if (noResponse) {
            console.log('Annotation server timeout...');
            abortController.abort();
            // how is the promise resolved/rejected when there's a timeout??
        }
    }, SERVER_TIMEOUT);
    const options = {
        method: method,
        signal: abortController.signal
    };
    let url = `${__classPrivateFieldGet(this, _AnnotationService_serverEndpoint, "f")}/${endpoint}`;
    const sessionKey = Cookies.get('annotation-key') || '';
    if (method === 'GET') {
        const params = [];
        for (const [key, value] of Object.entries(parameters)) {
            params.push(`${key}=${encodeURIComponent(JSON.stringify(value))}`);
        }
        params.push(`key=${encodeURIComponent(userApiKey)}`);
        params.push(`session=${encodeURIComponent(sessionKey)}`);
        url += '?' + params.join('&');
        options['headers'] = {
            "Accept": "application/json; charset=utf-8",
            "Cache-Control": "no-store"
        };
    }
    else if (method === 'POST') {
        const params = Object.assign({
            key: userApiKey,
            session: sessionKey
        }, parameters);
        options['body'] = JSON.stringify(params);
        options['headers'] = {
            "Accept": "application/json; charset=utf-8",
            "Content-Type": "application/json; charset=utf-8",
            "Cache-Control": "no-store"
        };
    }
    const response = await fetch(url, options);
    noResponse = false;
    if (response.ok) {
        return Promise.resolve(await response.json());
    }
    else {
        __classPrivateFieldSet(this, _AnnotationService_currentError, { error: `${response.status} ${response.statusText}` }, "f");
        return Promise.resolve(__classPrivateFieldGet(this, _AnnotationService_currentError, "f"));
    }
};
//==============================================================================
